package com.broadsoft.platform.wfengine.runtime.nodehandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broadsoft.platform.wfengine.NodeType;
import com.broadsoft.platform.wfengine.parser.ParsedWorkflowDefinition;
import com.broadsoft.platform.wfengine.runtime.WfContext;
import com.broadsoft.platform.wfengine.runtime.impl.NodeExecutionServiceImpl;

public class JoinNodeExecutionHandler implements INodeExecutionHandler {

    private final static Logger logger = LoggerFactory.getLogger(NodeExecutionServiceImpl.class);

    public JoinNodeExecutionHandler(ParsedWorkflowDefinition parsedWorkflowInfo){
        this.parsedWorkflowInfo=parsedWorkflowInfo; 
        
    }
    
    @Override
    public NodeType executeNode(NodeType currentNode, WfContext flowContext) {
        if (logger.isTraceEnabled()) {
            logger.trace("The method[executeJoinNode] begin");
        }
        NodeType nextNodeType = null;
        NodeType previousNode = flowContext.getPreviousNode();
        String flowName = flowContext.getWorkflowType().getName();
        
        Object mapOfFlow = flowContext.getParentWfContext().getMapOfJoinNode().get(flowName);
        List<NodeType> listOfNodeTypeSource = parsedWorkflowInfo.getAllSourceNodeByDestNodeName(flowName, currentNode
                .getName());
        int sizeOfSource = listOfNodeTypeSource.size(); 
        if (null == mapOfFlow) { 
            Map<String, List<NodeType>> mapOfNode = new HashMap<String, List<NodeType>>();
            List<NodeType> listOfNodeTypeOnJoining = new ArrayList<NodeType>();
            listOfNodeTypeOnJoining.add(previousNode);
            mapOfNode.put(currentNode.getName(), listOfNodeTypeOnJoining);
            flowContext.getParentWfContext().getMapOfJoinNode().put(flowName, mapOfNode);
            if (logger.isDebugEnabled()) {
                logger.debug("The join node[{}] is waiting for the other branchs reaching.",currentNode.getName()); 
            }
        } else {
            int sizeOnJoing = flowContext.getParentWfContext().getMapOfJoinNode().get(flowName).get(currentNode.getName()).size(); 
            if (sizeOfSource <= (sizeOnJoing + 1)) { 
                flowContext.setPreviousNode(currentNode);
                String destNodeName = currentNode.getDestNode().get(0);
                nextNodeType = parsedWorkflowInfo.getNodeTypeByName(flowName, destNodeName);
                return nextNodeType;
            } else { 
                flowContext.getParentWfContext().getMapOfJoinNode().get(flowName).get(currentNode.getName()).add(previousNode);
                if (logger.isDebugEnabled()) {
                    logger.debug("The join node[{}] is waiting for the other branchs reaching.",currentNode.getName()); 
                }
            }

        }
        if (logger.isTraceEnabled()) {
            logger.trace("The local variable[nextNodeType] is {}.", nextNodeType);
            logger.trace("The method[executeJoinNode] end");
        }
        return nextNodeType;
    }

    private ParsedWorkflowDefinition parsedWorkflowInfo;

    public ParsedWorkflowDefinition getParsedWorkflowInfo() {
        return parsedWorkflowInfo;
    }

    public void setParsedWorkflowInfo(ParsedWorkflowDefinition parsedWorkflowInfo) {
        this.parsedWorkflowInfo = parsedWorkflowInfo;
    }
}
